package cn.fintecher.gis.web;

import cn.fintecher.gis.annotation.CurrentOperator;
import cn.fintecher.gis.entity.*;
import cn.fintecher.gis.enums.CommonState;
import cn.fintecher.gis.exception.BadRequestException;
import cn.fintecher.gis.model.request.*;
import cn.fintecher.gis.model.response.OperatorListResponse;
import cn.fintecher.gis.model.response.OperatorLoginResponse;
import cn.fintecher.gis.model.response.OperatorResponse;
import cn.fintecher.gis.model.session.SessionModel;
import cn.fintecher.gis.respository.DepartmentRepository;
import cn.fintecher.gis.respository.OperatorRepository;
import cn.fintecher.gis.respository.RoleInfoRepository;
import cn.fintecher.gis.service.OperatorService;
import com.google.common.collect.Sets;
import com.querydsl.core.BooleanBuilder;
import io.swagger.annotations.*;
import org.modelmapper.ModelMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.http.ResponseEntity;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import springfox.documentation.annotations.ApiIgnore;

import java.util.*;

/**
 * Created by ChenChang on 2017/8/4.
 */
@RestController
@RequestMapping("/api/operator")
@Api(value = "管理员相关", description = "管理员相关")
public class OperatorController {
    private final Logger log = LoggerFactory.getLogger(OperatorController.class);

    private final String passWord = "888888";//默认密码

    @Autowired
    private OperatorRepository operatorRepository;
    @Autowired
    private OperatorService operatorService;
    @Autowired
    private DepartmentRepository departmentRepository;
    @Autowired
    private RoleInfoRepository roleInfoRepository;
    @Autowired
    private ModelMapper modelMapper;

    @ApiOperation(value = "管理员登录", notes = "管理员登录")
    @PostMapping(value = "/login")
    public ResponseEntity<OperatorLoginResponse> login(@Validated @RequestBody OperatorLoginRequest request) {
        log.debug("用户登录请求: {}", request);
        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
        QOperator qOperator = QOperator.operator;
        if (!operatorRepository.exists(qOperator.username.eq(request.getUsername()))) {
            throw new BadRequestException("login", "login.wrong.username");
        }
        Operator operator = operatorRepository.findOne(qOperator.username.eq(request.getUsername())).get();
        if (!passwordEncoder.matches(request.getPassword(), operator.getPassword())) {
            throw new BadRequestException("login", "login.wrong.password");
        }
        String token = UUID.randomUUID().toString();

        operatorService.operatorLogin(operator, token);
        OperatorResponse operatorResponse = operatorService.mergeOperator(operator);
        return ResponseEntity.ok()
                .body(new OperatorLoginResponse(token, operatorResponse));
    }

    @PostMapping("/createOperator")
    @ApiOperation(value = "用户的添加", notes = "用户的添加")
    public ResponseEntity<Operator> createOperator(@Validated @RequestBody CreateOperatorRequest request) {
        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
//        String password = "888888" ;//密码默认
        request.setPassword(passwordEncoder.encode(passWord));
        log.debug("REST request to save Operator : {}", request);
        QOperator qOperator = QOperator.operator;
        if (operatorRepository.exists(qOperator.username.eq(request.getUsername()))) {
            throw new BadRequestException("addOperator", "operator.is.exist");
        }
        Optional<Department> departmentOptional = departmentRepository.findById(request.getDepartmentId());
        departmentOptional.orElseThrow(() -> new BadRequestException(Department.class.getSimpleName(), "department.is.not.exist"));
        Department department = departmentOptional.get();
        Operator operator = new Operator();
        operator.setDepartment(department);
        operator.setPassword(request.getPassword());
        operator.setUsername(request.getUsername());
        operator.setUserTitle(request.getUserTitle());
        operator.setUserStatus(request.getUserStatus());
        Operator result = operatorRepository.save(operator);
        return ResponseEntity.ok()
                .body(result);
    }

    @PostMapping("/updateOperator")
    @ApiOperation(value = "用户的更新", notes = "用户的更新")
    public ResponseEntity<Void> updateOperator(@Validated @RequestBody OperatorRequest request) {
        Optional<Operator> operatorOption = operatorRepository.findById(request.getId());
        operatorOption.orElseThrow(() -> new BadRequestException(Operator.class.getSimpleName(), "Operator.is not exit"));
        Operator operator = operatorOption.get();
        operator.setUsername(request.getUsername());
        Optional<Department> departmentOptional = departmentRepository.findById(request.getDepartmentId());
        departmentOptional.orElseThrow(() -> new BadRequestException(Department.class.getSimpleName(), "role.is.not.exist"));
        Department department = departmentOptional.get();
        operator.setDepartment(department);
        operator.setUserStatus(request.getUserStatus());
        operator.setUserTitle(request.getUserTitle());
        operatorRepository.saveAndFlush(operator);
        return ResponseEntity.ok().build();
    }

    @PostMapping("/updateOperatorAndRole")
    @ApiOperation(value = "用户的维护角色", notes = "用户的维护角色")
    public ResponseEntity<Void> updateOperatorAndRole(@Validated @RequestBody OperatorRequest request) {
        Optional<Operator> operatorOption = operatorRepository.findById(request.getId());
        operatorOption.orElseThrow(() -> new BadRequestException(Operator.class.getSimpleName(), "Operator.is not exit"));
        Operator operator = operatorOption.get();
        if (request.getRoleIds() != null && request.getRoleIds().size() > 0) {
            Iterable<RoleInfo> iterable = roleInfoRepository.findAll(QRoleInfo.roleInfo.id.in(request.getRoleIds()));
            Set<RoleInfo> set = Sets.newHashSet(iterable);
            operator.setRoles(set);
        }else{
            operator.setRoles(null);
        }
        operatorRepository.save(operator);
        return ResponseEntity.ok().build();
    }


    @ApiOperation(value = "修改密码", notes = "修改密码")
    @PostMapping(value = "/changeOperatorPassword")
    public ResponseEntity<Void> changeOperatorPassword(@RequestBody @Validated ChangeOperatorPasswordRequest request, @RequestHeader(value = "X-OperatorToken") @ApiParam("用户Token") String token) {
        SessionModel sessionModel = operatorService.findOperatorByToken(token);
        Operator operator=operatorRepository.findById(sessionModel.getId()).get();
        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
        if (!passwordEncoder.matches(request.getOldPassword(), operator.getPassword())) {
            throw new BadRequestException("changeOperatorPassword", "oldPassword.is.wrong");
        }
        operator.setPassword(passwordEncoder.encode(request.getNewPassword()));
        operatorRepository.save(operator);
        return ResponseEntity.ok().build();
    }


    @PostMapping("/restPassword")
    @ApiOperation(value = "重置密码", notes = "重置密码")
    public ResponseEntity<Void> restPassword(@RequestBody ParamIdsRequest request) {
        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
        String password = passwordEncoder.encode(passWord);
        Iterator<Operator> iterator = operatorRepository.findAll(QOperator.operator.id.in(request.getIds())).iterator();
        List<Operator> operatorList = new ArrayList<>();
        while (iterator.hasNext()) {
            Operator operator = iterator.next();
            operator.setPassword(password);
            operatorList.add(operator);
        }
        operatorRepository.saveAll(operatorList);
        return ResponseEntity.ok().body(null);
    }

    @GetMapping("/getOperators")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "page", dataType = "int", paramType = "query",
                    value = "页数 (0..N)"),
            @ApiImplicitParam(name = "size", dataType = "int", paramType = "query",
                    value = "每页大小."),
            @ApiImplicitParam(name = "sort", allowMultiple = true, dataType = "string", paramType = "query",
                    value = "依据什么排序: 属性名(,asc|desc). ")
    })
    public ResponseEntity<Page<OperatorListResponse>> getOperators(Pageable pageable, QueryOperatorRequest request) {
        log.debug("REST request to get all of Operator");
        BooleanBuilder builder = new BooleanBuilder();
        QOperator qOperator = QOperator.operator;
        builder.and(qOperator.id.ne("1111111111111111"));
        if(request.getDepartmentId() != null){
            Optional<Department> optional = departmentRepository.findById(request.getDepartmentId());
            if(optional.isPresent()){
                Department department = optional.get();
                builder.and(qOperator.department.departmentCode.contains(department.getDepartmentCode()));
            }
        }
        if(request.getUsername() != null){
            builder.and(qOperator.username.eq(request.getUsername()));
        }
        Page<Operator> allList = operatorRepository.findAll(builder, pageable);
        List<Operator> operators = allList.getContent();
        List<OperatorListResponse> operatorListResponses = new ArrayList<>();
        for(Operator operator : operators){
            OperatorListResponse operatorListResponse = new OperatorListResponse();
            operatorListResponse.setId(operator.getId());
            operatorListResponse.setUsername(operator.getUsername());
            operatorListResponse.setUserTitle(operator.getUserTitle());
            operatorListResponse.setDepartmentId(operator.getDepartment().getId());
            operatorListResponse.setDepartmentName(operator.getDepartment().getDepartmentName());
            operatorListResponse.setUserStatus(operator.getUserStatus());
            List<String> roleIds = new ArrayList<>();
            Set<RoleInfo> set = operator.getRoles();
            for(RoleInfo roleInfo : set){
                roleIds.add(roleInfo.getId());
            }
            operatorListResponse.setRoleIds(roleIds);
            operatorListResponses.add(operatorListResponse);
        }
        Page<OperatorListResponse> page = new PageImpl<>(operatorListResponses, allList.getPageable(), allList.getTotalElements());

        return ResponseEntity.ok().body(page);
    }

    @GetMapping("/getOperatorByDepartmentId")
    @ApiOperation(value = "根据机构id查询所有的用户",notes = "根据机构id查询所有的用户")
    public ResponseEntity<List<OperatorListResponse>> getOperatorByDepartmentId(@RequestParam(value = "departmentId", required = false) String departmentId,
                                                                                @ApiIgnore @CurrentOperator SessionModel sessionModel) {
        BooleanBuilder builder = new BooleanBuilder();
        QOperator qOperator = QOperator.operator;
        if (departmentId != null && !departmentId.isEmpty()) {
            builder.and(qOperator.department.id.eq(departmentId));
        }
        builder.and(qOperator.id.ne(sessionModel.getId()));
        builder.and(qOperator.id.ne("1111111111111111"));
        Iterator<Operator> iterator = operatorRepository.findAll(builder).iterator();
        List<OperatorListResponse> operatorListResponses = new ArrayList<>();
        while (iterator.hasNext()){
            Operator operator = iterator.next();
            OperatorListResponse operatorListResponse = new OperatorListResponse();
            BeanUtils.copyProperties(operator, operatorListResponse);
            operatorListResponse.setDepartmentId(operator.getDepartment().getId());
            operatorListResponse.setDepartmentName(operator.getDepartment().getDepartmentName());
            List<String> roleIds = new ArrayList<>();
            Set<RoleInfo> set = operator.getRoles();
            for(RoleInfo roleInfo : set){
                roleIds.add(roleInfo.getId());
            }
            operatorListResponse.setRoleIds(roleIds);
            operatorListResponses.add(operatorListResponse);
        }
        return ResponseEntity.ok().body(operatorListResponses);
    }

    @GetMapping("/getOperatorListByRoleId")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "page", dataType = "int", paramType = "query",
                    value = "页数 (0..N)"),
            @ApiImplicitParam(name = "size", dataType = "int", paramType = "query",
                    value = "每页大小."),
            @ApiImplicitParam(name = "sort", allowMultiple = true, dataType = "string", paramType = "query",
                    value = "依据什么排序: 属性名(,asc|desc). ")
    })
    public ResponseEntity<Page<OperatorListResponse>> getOperatorListByRoleId(Pageable pageable, String roleId) {
        log.debug("REST request to get all of Operator");
        BooleanBuilder builder = new BooleanBuilder();
        QOperator qOperator = QOperator.operator;
        Optional<RoleInfo> optional = roleInfoRepository.findById(roleId);
        if(optional.isPresent()) {
            RoleInfo roleInfo = optional.get();
            if(roleInfo.getRoleStatus().equals(CommonState.ENABLED)) {
                builder.and(qOperator.roles.contains(roleInfo));
                Page<Operator> allList = operatorRepository.findAll(builder, pageable);
                List<Operator> operators = allList.getContent();
                List<OperatorListResponse> operatorListResponses = new ArrayList<>();
                for (Operator operator : operators) {
                    OperatorListResponse operatorListResponse = new OperatorListResponse();
                    operatorListResponse.setId(operator.getId());
                    operatorListResponse.setUsername(operator.getUsername());
                    operatorListResponse.setUserTitle(operator.getUserTitle());
                    operatorListResponse.setDepartmentId(operator.getDepartment().getId());
                    operatorListResponse.setDepartmentName(operator.getDepartment().getDepartmentName());
                    operatorListResponse.setUserStatus(operator.getUserStatus());
                    List<String> roleIds = new ArrayList<>();
                    roleIds.add(roleId);
                    operatorListResponse.setRoleIds(roleIds);
                    operatorListResponses.add(operatorListResponse);
                }
                Page<OperatorListResponse> page = new PageImpl<>(operatorListResponses, allList.getPageable(), allList.getTotalElements());

                return ResponseEntity.ok().body(page);
            }else{
                return ResponseEntity.ok().body(null);
            }
        }else{
            return ResponseEntity.ok().body(null);
        }
    }
}
